package org.erpworld.hr.dao;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

/**
 * Bu class SQL java clasını eşlemek için kullanılır.user tablosuna erişmek ve crud işemlerini
 * gerçekleştirir.
 *
 * @author Volkan
 */
public  class UserDAO extends HibernateDAO {
    private final Logger log = LoggerFactory.getLogger(UserDAO.class);
    

    // Sabitler ----------------------------------------------------------------------------------
    
    private static final String USERNAME_PASSWORD_Q = "from User as u where u.username=? and u.password=?";
    private static final String ALL_USER_BY_ID = "from User u order by  u.id";
    // Değişkenler ------------------------------------------------------------------------------------

    // Actions ------------------------------------------------------------------------------------

    /**
     * user id ye göre user çeker.     *
     *
     * @param id Userid.
     * @return Userid ile eşleşen Userı dömdürür.Yoksa Null döndürür..
     */
    public User find(Integer id) {
        log.info("ID ye göre User çekiliyor. Id: " + id);
        try {
            return (User) getSession().get(User.class, id);
        } catch (HibernateException e) {
            log.error("ID ye göre User getirme sırasında hata oluştu", e);
            throw e;
        }
    }

    /**
     * UserName ve password göre user çeker.
     *
     * @param username Username
     * @param password Password.
     * @return user ve Passwordle eşleşen Userı döndürür.Eşlenme Olmazsa null döndürür.
     * @throws RuntimeException Database katmanında  herhangi bir hata ile karşılaşıldığında..
     */
    public User find(String username, String password) {
        log.info("Kullanıcı adı ve password u eşleşen User çekiliyor...");
        try {
            getSession().getTransaction().begin();
            return (User) getSession().createQuery(USERNAME_PASSWORD_Q).setParameter(0, username).setParameter(1, password);
        } catch (HibernateException e) {
            log.error("Propertyi göre user sırasında hata oluştu.  ", e);
            throw e;
        }
    }

    /**
     * verilen sütun isme ve değerine göre user çeker.Diğer find metodları için basamaktır.
     *
     * @param column Sütun..
     * @param deger  Sütun değeri.
     * @return Sütun ve değerler neticesindeki user ı döndürür.Eşleme yoksa null dündürür..
     * @throws RuntimeException Database katmanında  herhangi bir hata ile karşılaşıldığında..
     */
    private List<User> find(String column, Object... deger) {
        log.info("Propertye göre Userlar çekiliyor...Property" + column + " Deger :" + deger);
        try {
            String queryString = String.format("from User as u where u.%s=?", column);
            Query queryOb = getSession().createQuery(queryString);
            queryOb.setParameter(0, deger);
            return queryOb.list();
        } catch (HibernateException e) {
            log.error("Propertyi göre user bulma sırasında hata oluştu.  ", e);
            throw e;
        }
    }

    /**
     * Database katmanında bütün Userları ID ye göre sıralayıp getirir.Eğer kayıtlı user yoksa
     * null yada boş döndürmez.
     *
     * @return Database katmanında bütün Userları ID ye göre sıralayıp getirir
     * @throws RuntimeException Database katmanında  herhangi bir hata ile karşılaşıldığında..
     */
    public List<User> list() {
        log.info("Tüm Userlar getiriliyor...");
        try {
            getSession().getTransaction().begin();
            List userss = getSession().createQuery(ALL_USER_BY_ID).list();
            getSession().getTransaction().commit();
            return userss;
        } catch (HibernateException e) {
            log.error("Bütün Userları getirme sırasında hata oluştu.", e);
            throw e;
        }
    }

    /**
     * Verilen userı DB ye kayıt eder.user ID null olmalıdır yoksa IllegalArgumentException fırlatır.
     * Eğer Id nin varolup olmadığı bilinmiyorsa   kullanılmalıdır.
     * Kayıt eklendikten sonra ID oluşacaktır.
     *
     * @param user DB ye eklenecek user.
     */
    public void create(User user) {
        log.info("Yeni User olusturuluyor.....");
        if (user.getId() != null) {
            log.error("User ID si null değil . User oluşturma başarısız .", new Throwable(new IllegalArgumentException()));
        }
        try {
            getSession().getTransaction().begin();
            getSession().save(user);
            getSession().getTransaction().commit();
        } catch (HibernateException e) {
            log.error("User oluşturma sırasında hata oluştu.", e);
            throw e;
        }
    }

    /**
     * Verilen Userı DB de güncellemek için kullanılır.ID null olmamalıdır,yoksa IllegalArgumentException fırlatılır.
     * Eğer Id nin varolup olmadığı bilinmiyorsa   kullanılmalıdır.
     *
     * @param user DB de güncellenecek user.
     * @throws IllegalArgumentException user ID null ise fırlatılır.
     */
    public void update(User user) {

        log.info("User güncelleniyor.....");
        if (user.getId() == null) {
            log.error("Böyle bir kullanıcı yok. ID null.", new Throwable(new IllegalArgumentException()));
        }
        try {
            getSession().saveOrUpdate(user);
        } catch (HibernateException e) {
            log.error("User güncelleme esnasında hata oluştu ...", e);
            throw e;
        }

    }

    /**
     * Verilen Userı DB ye kayıt eder. Eğer ID null ise,
     * null değil ise  metodlarını kullanır.
     *
     * @param user DB ye Eklenecek user.
     */
    public void save(User user) {
        if (user.getId() == null) {
            create(user);
        } else {
            update(user);
        }
    }

    /**
     * Verilen Userı DB den siler.Silme işleminden sonra silinen userın ID si Null olur.
     *
     * @param user DB den silinecek user.
     */
    public void delete(User user) {
        log.info("User siliniyor...");
        try {
            getSession().getTransaction().begin();
            getSession().delete(user);
            getSession().getTransaction().commit();

        } catch (HibernateException e) {
            log.error("User silme sırasında hata oluştu.", e);
            throw e;
        }
    }

    /**
     * Usernamein DB de olup olmadığını kontrol eder.
     *
     * @param username Kontrol edilecek Username.
     * @return Eğer verilen Username DB de varsa True döndürür.
     */
    public boolean existUsername(String username) {
        return !getSession().createQuery("from User u where u.username=?").setParameter(0, username).list().isEmpty();
    }

    /**
     * Verilen emailin DB de olup olmadığınıu kontrol eder.
     *
     * @param email Kontrol edilecek email.
     * @return Eğer verilen email DB de varsa True döndürür..
     */
    public boolean existEmail(String email) {
        return !getSession().createQuery("from User u where u.email=?").setParameter(0, email).list().isEmpty();
    }

    // Yardımcılar ------------------------------------------------------------------------------------


}